#include "gl_render.h"
#include "matrix.h"


auto gVertexShader =
        "uniform mat4 uModelMatrix;\n"
        "attribute vec4 aPosition;\n"
        "attribute vec2 a_TexCoord;\n"
        "varying vec2 v_TexCoord;\n"
        "void main() {\n"
        "  gl_Position = uModelMatrix * aPosition;\n"
        "  v_TexCoord = a_TexCoord;\n"
        "}\n";

auto gFragmentShader =
        "precision mediump float;\n"
        "uniform sampler2D samplerY;\n"
        "uniform sampler2D samplerU;\n"
        "uniform sampler2D samplerV;\n"
        "varying vec2 v_TexCoord;\n"
        "void main() {\n"
        "   vec3 yuv;\n"
        "   vec3 rgb;\n"
        "   yuv.x = texture2D(samplerY, v_TexCoord).r;\n"
        "   yuv.y = texture2D(samplerU, v_TexCoord).r - 0.5;\n"
        "   yuv.z = texture2D(samplerV, v_TexCoord).r - 0.5;\n"
        "   rgb = mat3(1, 1, 1, 0, -0.39465,  2.03211, 1.13983, -0.58060, 0) * yuv;\n"
        "   gl_FragColor = vec4(rgb, 1);\n"
        "}\n";


//const GLfloat gTriangleVertices[] = {
//        -1.0f, 1.0f,  0.0f, 1 - 1.0f,
//        -1.0f, -1.0f, 0.0f, 1 - 0.0f,
//        1.0f,  1.0f,  1.0f, 1 - 1.0f,
//        1.0f,  -1.0f, 1.0f, 1 - 0.0f};

const GLfloat gTriangleVertices[] = {
        -1.0f, 1.0f,  0.0f, 1 - 1.0f,
        -1.0f, -1.0f, 0.0f, 1 - 0.0f,
        1.0f,  1.0f,  1.0f, 1 - 1.0f,
        1.0f,  -1.0f, 1.0f, 1 - 0.0f};


GLuint gProgram;
GLuint gaPositionHandle;
GLuint gaTexCoordHandle;
GLuint gModelMatrixHandle;
GLuint uTextureSamplerYHandle;
GLuint uTextureSamplerUHandle;
GLuint uTextureSamplerVHandle;


void gl_init(int rotate, int width, int height){

    glViewport(0, 0, width, height);

    gProgram = linkProgram(gVertexShader, gFragmentShader);
    if (!gProgram) {
        LOGE("Could not create program.");
        return;
    }

    glUseProgram(gProgram);

    gaPositionHandle = glGetAttribLocation(gProgram, "aPosition");
    glVertexAttribPointer(gaPositionHandle, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), gTriangleVertices);
    glEnableVertexAttribArray(gaPositionHandle);

    gaTexCoordHandle = glGetAttribLocation(gProgram, "a_TexCoord");
    glVertexAttribPointer(gaTexCoordHandle, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), gTriangleVertices + 2);
    glEnableVertexAttribArray(gaTexCoordHandle);

    gModelMatrixHandle = glGetUniformLocation(gProgram, "uModelMatrix");

    GLfloat mModelMatrix[16];
    if (rotate != 0) {
        rotate = -rotate;
    }
    setRotateM(mModelMatrix, 0, rotate, 0.0f, 0.0f, 1.0f);

    glUniformMatrix4fv(gModelMatrixHandle, 1, GL_FALSE, mModelMatrix);

    uTextureSamplerYHandle = glGetUniformLocation(gProgram, "samplerY");
    uTextureSamplerUHandle = glGetUniformLocation(gProgram, "samplerU");
    uTextureSamplerVHandle = glGetUniformLocation(gProgram, "samplerV");

    LOGD("----------------------init width:%d, height:%d", width, height);
}

void gl_render(char * yuvDataBuf, int yuv_width, int yuv_height) {
    GLuint textureYID;
    GLuint textureUID;
    GLuint textureVID;

    glGenTextures(1, &textureYID);
    glGenTextures(1, &textureUID);
    glGenTextures(1, &textureVID);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, textureYID);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, yuv_width, yuv_height,
                 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, yuvDataBuf);
    glGenerateMipmap(GL_TEXTURE_2D);
    glUniform1i(uTextureSamplerYHandle, 0);


    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, textureUID);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, yuv_width/2, yuv_height/2,
                 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, yuvDataBuf + yuv_width * yuv_height);
    glGenerateMipmap(GL_TEXTURE_2D);
    glUniform1i(uTextureSamplerUHandle, 1);


    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_2D, textureVID);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, yuv_width/2, yuv_height/2,
                 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, yuvDataBuf + yuv_width * yuv_height * 5 / 4);
    glGenerateMipmap(GL_TEXTURE_2D);
    glUniform1i(uTextureSamplerVHandle, 2);


    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    glBindTexture(GL_TEXTURE_2D, 0);
    glDeleteTextures(1, &textureYID);
    glDeleteTextures(1, &textureUID);
    glDeleteTextures(1, &textureVID);

}
